#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// Defining specific pins on the 7-segment display to output pins
#define sgA PB5
#define sgB PB1
#define sgC PD6
#define sgD PB7
#define sgE PB6
#define sgF PB4
#define sgG PD7
#define DP PD5
#define D2 PB3
#define D3 PB2
#define D4 PB0


// The following functions, when called, will display their cooresponding
// numbers on the 7-segment specified by the passed parameter (2, 3, or 4)
// The decimal point of the temperature is always lit on the display

void zero(int seg) // AFEDCB
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgF)|(1<<sgE)|(1<<sgD)|(1<<sgB);
	PORTD |= (1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void one(int seg) // BC
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgB);
	PORTD |= (1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void two(int seg) // ABGED
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgB)|(1<<sgE)|(1<<sgD);
	PORTD |= (1<<sgG);
	if(seg==D3) PORTD |= (1<<DP);
}

void three(int seg) // ABGCD
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgB)|(1<<sgD);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void four(int seg) // FGBC
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgF)|(1<<sgB);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void five(int seg) // AFGCD
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgF)|(1<<sgD);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void six(int seg) // AFGCDE
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgF)|(1<<sgD)|(1<<sgE);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void seven(int seg) // ABC
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgB);
	PORTD |= (1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void eight(int seg) // ABCDEFG
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgB)|(1<<sgD)|(1<<sgE)|(1<<sgF);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void nine(int seg) // AFGBC
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgA)|(1<<sgF)|(1<<sgB);
	PORTD |= (1<<sgG)|(1<<sgC);
	if(seg==D3) PORTD |= (1<<DP);
}

void other(int seg) // DFB
{
	PORTB = 0;
	PORTD = 0;
	
	PORTB |= (1<<seg);
	PORTB |= (1<<sgD)|(1<<sgF)|(1<<sgB);
	if(seg==D3) PORTD |= (1<<DP);
}

uint16_t ReadADC(uint8_t ADCchannel)
{
	//select ADC channel with safety mask
	ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);
	//single conversion mode
	ADCSRA |= (1<<ADSC);
	// wait until ADC conversion is complete
	while( ADCSRA & (1<<ADSC) );
	return ADC;
}

int main()
{
	// Set Ports B and D as outputs
	DDRB = 0xFF;
	DDRD = 0xFF;
	// Select Vref=AVcc
	ADMUX |= (1<<REFS0);
	//set prescaller to 8 and enable ADC
	ADCSRA |= (1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);
	
	while(1)
	{
		int temp = ReadADC(0)*5; // read the ADC value and perform conversion to temperature
		// the LM34 temperature conversion is 10mV/1 degree Farenheit
		// temperature = (ADC*5000mV)/1024 = ~5*ADC
		int dig3 = temp; // dig3 is the tenths place digit always displayed on the 4th 7-segment
		dig3=dig3%10;
		
		if(dig3==0) zero(D4);
		else if(dig3==1) one(D4);
		else if(dig3==2) two(D4);
		else if(dig3==3) three(D4);
		else if(dig3==4) four(D4);
		else if(dig3==5) five(D4);
		else if(dig3==6) six(D4);
		else if(dig3==7) seven(D4);
		else if(dig3==8) eight(D4);
		else if(dig3==9) nine(D4);
		else other(D4); // this function was used for troubleshooting to determine whether
		// the ADC returned a valid value
		
		int dig2 = temp/10; // dig2 is the ones place digit always displayed on the 3rd 7-segment
		dig2 = dig2%10;
		
		if(dig2==0) zero(D3);
		else if(dig2==1) one(D3);
		else if(dig2==2) two(D3);
		else if(dig2==3) three(D3);
		else if(dig2==4) four(D3);
		else if(dig2==5) five(D3);
		else if(dig2==6) six(D3);
		else if(dig2==7) seven(D3);
		else if(dig2==8) eight(D3);
		else if(dig2==9) nine(D3);
		else other(D3);
		
		int dig1 = temp/100;
		dig1 = dig1%10; // dig1 is the tens place digit always displayed on the 2nd 7-segment
		
		if(dig1==0) zero(D2);
		else if(dig1==1) one(D2);
		else if(dig1==2) two(D2);
		else if(dig1==3) three(D2);
		else if(dig1==4) four(D2);
		else if(dig1==5) five(D2);
		else if(dig1==6) six(D2);
		else if(dig1==7) seven(D2);
		else if(dig1==8) eight(D2);
		else if(dig1==9) nine(D2);
		else other(D2);
		
	}
	
}
